package gov.nasa.anml.lifted;

import java.util.ArrayList;

import gov.nasa.anml.PDDL;
import gov.nasa.anml.State;
import gov.nasa.anml.PDDL.Time;
import gov.nasa.anml.utility.SimpleBoolean;
import gov.nasa.anml.utility.SimpleFloat;
import gov.nasa.anml.utility.SimpleObject;

public class Undefine<T extends SimpleObject<? super T>> extends ChainableExpressionImp<T,T>  {
	public Expression<T,T> left;
	
	public Undefine(Expression<T, T> e) {
		this.left = e;
	}

	public boolean apply(State p, int contextID, State c) {
		History<T> place = left.storage(p,c);
		// will throw nullpointerexception if left is not an l-value
//		if (place.locked)
//		return false;

		History<T> last = left.storage(p,p);
		int bra = c.bra;
		SimpleFloat start = c.start;
		// do generation of child from parent by copying and advancing time
		// (bra from before to at, simulate, to after, simulate,
		//  start to next time bra to before, simulate, done)

		place.value = null;
//		place.locked = true;
		place.prev = last;
		place.start = start;
		place.bra = bra;
		return true;
	}

	public T value(State s) {
		// if correctly applied, the assignment to null (undefined)
		// has taken place, and e.value(s) will return null
		return null;
		//return e.value(s);
	}

	public History<T> storage(State p, State c) {
		return left.storage(p,c);
	}

	public TypeCode typeCode() {
		return left.typeCode();
	}
	
	public void translateDecl(PDDL pddl, Interval unit) {
		left.translateDecl(pddl,unit);
	}
	
	public void translateStmt(PDDL pddl, Interval unit, PDDL.Time part) {
		ArrayList<PDDL.BooleanExpression> conditions = unit.getPDDLConditions(); 
		ArrayList<PDDL.Effect> effects = unit.getPDDLEffects();
		switch(left.typeCode()) {
		case Boolean:
			PDDL.PredicateReference refB = (PDDL.PredicateReference) left.translateLValue(pddl,unit);
			// pretend false means undefined
			switch(part) {
			case Start:
			case End:
				effects.add(pddl.makeEffect(part,refB,false));
				break;
			case Interim:
				effects.add(pddl.makeEffect(PDDL.Time.Start,refB,false));
				conditions.add(pddl.wrap(PDDL.Time.Interim,pddl.makeTest(refB,false)));
				break;
			case All:
			case EndHalf:
				effects.add(pddl.makeEffect(PDDL.Time.End,refB,false));
			case StartHalf:
				effects.add(pddl.makeEffect(PDDL.Time.Start,refB,false));
				conditions.add(pddl.wrap(PDDL.Time.Interim,pddl.makeTest(refB,false)));
				break;
			default:
				System.err.println("New PDDL.Time constant unaccounted for in Undefine.");
			}
		case Float:
			PDDL.FunctionReference refF = (PDDL.FunctionReference) left.translateLValue(pddl,unit);
			switch(part) {
			case Start:
			case End:
				effects.add(pddl.makeEffect(part,refF,pddl.FloatUndefined));
				break;
			case Interim:
				effects.add(pddl.makeEffect(PDDL.Time.Start,refF,pddl.FloatUndefined));
				break;
			case All:
			case EndHalf: // PDDL can't do effects just after start, so I settle for at start.
				effects.add(pddl.makeEffect(PDDL.Time.End,refF,pddl.FloatUndefined));
			case StartHalf:
				effects.add(pddl.makeEffect(PDDL.Time.Start,refF,pddl.FloatUndefined));
				break;
			default:
				System.err.println("New PDDL.Time constant unaccounted for in Undefine.");
			}
		default:
			System.err.println("Oops!");
		}
	}




}


